package chapter_3.message.coder;

import chapter_3.message.entity.AbstractMessage;
import chapter_3.message.entity.Candidate;
import chapter_3.message.entity.RequestMessage;
import chapter_3.message.entity.ResponseMessage;

import java.io.*;

public class BinaryMessageCoder implements MessageCoder {

    private static final int MAGIC = 0x5400;
    private static final int MAGIC_MASK = 0xfc00;
    private static final int RESPONSE_FLAG = 0x0200;
    private static final int INQUIRY_FLAG = 0x0100;

    private static final int MIN_WIRE_LENGTH = 4;


    @Override
    public byte[] toWire(AbstractMessage message) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);

        short magicWithFlag = MAGIC;
        if (message.getResponseFlag()) {
            magicWithFlag |= RESPONSE_FLAG;
        }
        if (message.getInquiryFlag()) {
            magicWithFlag |= INQUIRY_FLAG;
        }

        dataOutputStream.writeShort(magicWithFlag);
        short candidateId;
        long voteNumber;
        if (message instanceof RequestMessage) {
            candidateId = ((RequestMessage) message).getCandidateId().shortValue();
            dataOutputStream.writeShort(candidateId);
        } else {
            Candidate candidate = ((ResponseMessage) message).getCandidate();
            candidateId = candidate.getId().shortValue();
            voteNumber = (long) candidate.getVoteNumber();
            dataOutputStream.writeShort(candidateId);
            dataOutputStream.writeLong(voteNumber);
        }
        dataOutputStream.flush();
        byte[] data = byteArrayOutputStream.toByteArray();
        return data;
    }

    @Override
    public AbstractMessage fromWire(byte[] bytes) throws IOException {
        if (bytes.length < MIN_WIRE_LENGTH) {
            throw new IOException("消息长度不符合条件");
        }
        boolean responseFlag;
        boolean inquiryFlag;
        int candidateId;
        long voteNumber;
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        DataInputStream inputStream = new DataInputStream(byteArrayInputStream);

        //先读取消息头的magic字段,判断消息头是否正确
        short magicWithFlag = inputStream.readShort();
        if ((magicWithFlag & MAGIC_MASK) != MAGIC) {
            throw new IOException("消息头格式错误");
        }
        responseFlag = (magicWithFlag & RESPONSE_FLAG) == RESPONSE_FLAG;
        inquiryFlag = (magicWithFlag & INQUIRY_FLAG) == INQUIRY_FLAG;

        candidateId = inputStream.readShort();
        if (candidateId < 0 || candidateId > 1000) {
            throw new IllegalArgumentException("候选人Id不能超出范围");
        }

        //如果是响应消息，还需要解析出候选人的票数，这里判断一下，票数不能为负数
        if (responseFlag) {
            voteNumber = inputStream.readLong();
            if (voteNumber < 0) {
                throw new IllegalArgumentException("得票数不能为负数");
            }
            Candidate candidate = new Candidate(candidateId, (int) voteNumber);
            AbstractMessage message = new ResponseMessage(inquiryFlag, candidate);
            return message;
        }
        AbstractMessage message = new RequestMessage(inquiryFlag, candidateId);
        return message;
    }
}
